package com.woniuxy.woniuhis.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.druid.util.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniuxy.woniuhis.entity.Emp;
import com.woniuxy.woniuhis.entity.Inpatient;
import com.woniuxy.woniuhis.entity.SurgeryBooking;
import com.woniuxy.woniuhis.entity.SurgeryExe;
import com.woniuxy.woniuhis.entity.SurgeryRoom;
import com.woniuxy.woniuhis.exception.InpatientServiceException;
import com.woniuxy.woniuhis.exception.SurgeryBookingServiceException;
import com.woniuxy.woniuhis.mapper.EmpMapper;
import com.woniuxy.woniuhis.mapper.InpatientMapper;
import com.woniuxy.woniuhis.mapper.SurgeryBookingMapper;
import com.woniuxy.woniuhis.mapper.SurgeryExeMapper;
import com.woniuxy.woniuhis.mapper.SurgeryRoomMapper;
import com.woniuxy.woniuhis.service.SurgeryBookingService;
import com.woniuxy.woniuhis.util.UUIDUtil;

@Service
public class SurgeryBookingServiceImpl implements SurgeryBookingService {

	@Autowired
	SurgeryBookingMapper surgeryBookingMapper;
	
	@Autowired
	SurgeryRoomMapper surgeryRoomMapper;
	
	@Autowired
	InpatientMapper inpatientMapper;
	
	@Autowired
	EmpMapper empMapper;
	
	@Autowired
	SurgeryExeMapper surgeryExeMapper;
	// 总起
	// 手术室 useStatus true 表示可用，false 表示不可用
	// 预约单 
	/* 预约单中的预约状态
		0 取消
		1 未执行（在预约状态）
		2 执行中（手术执行过程中）
		3 执行完成（手术执行完成）
		4 过期（已经过了预约开始的时间，手术没有开始则自动转换为过期）
	*/
	/**
	 * 添加手术预约记录
	 */
	@Override
	@Transactional
	public void addSurgeryBooking(SurgeryBooking surgeryBooking) {
		System.out.println(surgeryBooking);
		
		try {
			// 先查病人的信息，根据id查病人的信息
			// 获取病人的id,然后查出名字
			String inpatientId = surgeryBooking.getInpatientId();
			Inpatient inpatient = inpatientMapper.selectInpatientById(inpatientId);
			if(inpatient == null) {
				throw new InpatientServiceException("病人不存在");
			}
			surgeryBooking.setInpatientName(inpatient.getInpatientName());
			// 添加预约时，首先判断预定时段的手术室（自然状态）是否可用
			// 因为手术室管理中只有当前的状态，只有一个是否可用，因此就直接判定填写预约单的时刻到预定的开始时刻手术室都可用
			// 但是今天预约，手术室可用，且预定手术的时间为后天，明天把手术室的状态改为不可用，后天的时候如果去手术，则手术的状态是不可用的，但是预约的记录是存在的，
			// 如果已经预约的手术，都会安排，在手术室改状态的之前的预约单都会去做，但是后来的预约单去预约时，先去判断，手术室不能用，就不能用
			String surgeryRoomId = surgeryBooking.getSurgeryRoomId();
			SurgeryRoom surgeryRoom = surgeryRoomMapper.selectSurgeryRoomById(surgeryRoomId);
			if(!surgeryRoom.getUseStatus()) {
				// useStatus true 表示可用，false 表示不可用
				throw new SurgeryBookingServiceException("手术室不可用");
			}
			// 若手术室可用，接着判断想预约的手术室在想预约的时段是否已经有预约记录，
			// 拿预定开始的时间，预定结束的时间去数据库中撞，和数据库中的存的起始时间和结束时间进行碰撞
			// 既要用开始时间去碰撞，又要用结束的时间去碰撞检测
			int count = 0; 
			// 开始时间碰撞
			count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingStartTime(), surgeryBooking.getSurgeryRoomId());
			if(count > 0) {
				// 大于0，表示已经有预约记录了
				throw new SurgeryBookingServiceException("手术预约开始时间段不能使用");
			}
			// 结束结束时间碰撞
			count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingEndTime(), surgeryBooking.getSurgeryRoomId());
			if(count > 0) {
				// 大于0，表示已经有预约记录了
				throw new SurgeryBookingServiceException("手术预约结束时间段不能使用");
			}
			// 如果有预约记录，则不能添加预约信息，抛出不能预约的异常
			// 如果无预约记录，则添加预约信息
			surgeryBookingMapper.insertSurgeryBooking(surgeryBooking);
		} catch (Exception e) {
			e.printStackTrace();
			throw new SurgeryBookingServiceException(e.getMessage());
		}

	}

	/**
	 * 	更新手术手术预约记录
	 */
	@Override
	@Transactional
	public void modifySurgeryBooking(SurgeryBooking surgeryBooking) {
		try {
			// 首先查询预约单中是否有,controller中判断
			// 修改手术室的预约单时，如果取消预约，没有什么可以考虑的直接取消，单独的方法
			// 数据库中的记录
			SurgeryBooking sb = surgeryBookingMapper.selectSurgeryBookingById(surgeryBooking.getBookingId());
			if(sb == null) {
				throw new SurgeryBookingServiceException("手术预约单不存在");
			}
			if(!sb.getSurgeryRoomId().equals(surgeryBooking.getSurgeryRoomId())) {
				// 如果不同的手术室   不换时间或者换时间，都需要先去判断手术室是否可用，和增加手术的预约记录一样的
				// 判断手术室是否可用
				String surgeryRoomId = surgeryBooking.getSurgeryRoomId();
				SurgeryRoom surgeryRoom = surgeryRoomMapper.selectSurgeryRoomById(surgeryRoomId);
				if(!surgeryRoom.getUseStatus()) {
					// useStatus true 表示可用，false 表示不可用
					throw new SurgeryBookingServiceException("手术室不可用");
				}
				// 如果可用，判断预约的手术室的要预约的时间段能不能用
				int count = 0; 
				// 开始时间碰撞
				count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingStartTime(), surgeryBooking.getSurgeryRoomId());
				if(count > 0) {
					// 大于0，表示已经有预约记录了
					throw new SurgeryBookingServiceException("手术预约开始时间段不能使用");
				}
				// 结束结束时间碰撞
				count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingEndTime(), surgeryBooking.getSurgeryRoomId());
				if(count > 0) {
					// 大于0，表示已经有预约记录了
					throw new SurgeryBookingServiceException("手术预约结束时间段不能使用");
				}
				// 判断结束，如果要预约的手术室且要预约的时间段可以更新预约记录
				surgeryBookingMapper.updateSurgeryBooking(surgeryBooking);
			}else {
				// 如果在同一手术室换时间，先把自身的状态改为取消转台，如果能够提前，改时间该状态，如果不能改时间，把状态改回来，同时抛出异常
				// 先改状态
				SurgeryBooking temp = new SurgeryBooking();
				temp.setBookingId(surgeryBooking.getBookingId());
				temp.setSituation("0");
				surgeryBookingMapper.updateSurgeryBooking(temp);
				// 手术时间需要提前，则可以直接提前，不用判断手术室是否可用，因为假定手术室是预约时刻到预定开始时刻都能用，如果中途修改了手术室的状态，也假定能够使用
				if(surgeryBooking.getBookingEndTime().before(sb.getBookingEndTime())||surgeryBooking.getBookingEndTime().equals(sb.getBookingEndTime())) {
					int count = 0;
					// 开始时间碰撞
					count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingStartTime(), surgeryBooking.getSurgeryRoomId());
					if(count > 0) {
						// 大于0，表示已经有预约记录了
						throw new SurgeryBookingServiceException("手术预约开始时间段不能使用");
					}
					// 结束结束时间碰撞
					count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingEndTime(), surgeryBooking.getSurgeryRoomId());
					if(count > 0) {
						// 大于0，表示已经有预约记录了
						throw new SurgeryBookingServiceException("手术预约结束时间段不能使用");
					}
					surgeryBookingMapper.updateSurgeryBooking(surgeryBooking);
				}else {
					// 手术时间需要延后，两种情况第一种是缩短时间的延后，起始时间延后,结束时间
					// 则需要去判断手术室的状态，如果能用，则可以延后，如果不能用，直接抛出异常该手术室后面时间段不能用，换手术室延后时间
					if(surgeryBooking.getBookingStartTime().after(sb.getBookingStartTime()) &&
							(surgeryBooking.getBookingEndTime().before(sb.getBookingEndTime())||surgeryBooking.getBookingEndTime().equals(sb.getBookingEndTime())) ) {
						surgeryBookingMapper.updateSurgeryBooking(surgeryBooking);
					}else {
						String surgeryRoomId = surgeryBooking.getSurgeryRoomId();
						SurgeryRoom surgeryRoom = surgeryRoomMapper.selectSurgeryRoomById(surgeryRoomId);
						System.out.println(surgeryBooking);
						System.out.println(surgeryRoomId);
						System.out.println(surgeryRoom);
						if(!surgeryRoom.getUseStatus()) {
							// useStatus true 表示可用，false 表示不可用
							throw new SurgeryBookingServiceException("手术室不可用");
						}
						int count = 0;
						// 开始时间碰撞
						count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingStartTime(), surgeryBooking.getSurgeryRoomId());
						if(count > 0) {
							// 大于0，表示已经有预约记录了
							throw new SurgeryBookingServiceException("手术预约开始时间段不能使用");
						}
						// 结束结束时间碰撞
						count = surgeryBookingMapper.selectSurgeryBookingByDateForcollision(surgeryBooking.getBookingEndTime(), surgeryBooking.getSurgeryRoomId());
						if(count > 0) {
							// 大于0，表示已经有预约记录了
							throw new SurgeryBookingServiceException("手术预约结束时间段不能使用");
						}
						surgeryBookingMapper.updateSurgeryBooking(surgeryBooking);
					}
					
				}
				
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new SurgeryBookingServiceException(e.getMessage());
		}
	}

	/**
	 * 查询指定手术预约记录
	 */
	@Override
	public SurgeryBooking findSurgeryBookingById(String id) {
		try {
			return surgeryBookingMapper.selectSurgeryBookingById(id);
		} catch (Exception e) {
			e.printStackTrace();
			throw new SurgeryBookingServiceException("系统维护中");
		}
	}
	
	/**
	 * 查询所有的手术预约记录,查询符合条件的
	 * @param surgeryBooking
	 * @return
	 */
	@Override
	public PageInfo<SurgeryBooking> findSurgeryBookings(SurgeryBooking surgeryBooking, int pageIndex,int pageSize) {
		try {
			// 开启分页
			PageHelper.startPage(pageIndex, pageSize);
			//System.out.println(surgeryBooking);
			// 输入预约人的姓名，先模糊查询查预约人的信息
			String empName = null;
			if(surgeryBooking.getEmp() != null && !StringUtils.isEmpty(surgeryBooking.getEmp().getEmpName()))
				empName = surgeryBooking.getEmp().getEmpName();
			List<Emp> emps = null;
			// Spring中的工具类
			if(!StringUtils.isEmpty(empName)) {
				Emp temp = new Emp();
				temp.setEmpName(empName);
				emps = empMapper.selectEmpByCondition(temp);
			}
			List<SurgeryBooking> surgeryBookings = new ArrayList<SurgeryBooking>();
			// Spring中的工具类
			if(CollectionUtils.isEmpty(emps)) {
				// 模糊查询的员工姓名为空，就直接查
				surgeryBookings = surgeryBookingMapper.selectSurgeryBookings(surgeryBooking);
				// 给每一条的员工赋值，查询员工的信息，赋上姓名
				for(SurgeryBooking sb:surgeryBookings) {
					// 这里查询员工信息有问题
					
					Emp tempEmp = empMapper.selectEmpById(sb.getEmpId());
					if(tempEmp !=null)
						sb.setEmp(tempEmp);
				}
			}else {
				// 模糊查询员工姓名不为空，需要遍历emps,然后查询具体的每个医生或者护士的预约记录
				SurgeryBooking sbTemp = new SurgeryBooking();
				List<SurgeryBooking> sbTempList;
				for(Emp emp:emps) {
					sbTemp.setEmpId(emp.getEmpId());
					sbTempList = surgeryBookingMapper.selectSurgeryBookings(surgeryBooking);
					for(SurgeryBooking sb:sbTempList) {
						Emp tempEmp = empMapper.selectEmpById(sb.getEmpId());
						if(tempEmp !=null)
							sb.setEmp(tempEmp);
					}
					surgeryBookings.addAll(sbTempList);
				}
			}
			PageInfo<SurgeryBooking> pageInfo = new PageInfo<SurgeryBooking>(surgeryBookings);
			return pageInfo;
		} catch (Exception e) {
			e.printStackTrace();
			throw new SurgeryBookingServiceException(e.getMessage());
		}
	}
	
	/**
	 * 	更新手术状态，注意手术的状态可能出现回滚的情况
	 * 	* 	修改状态会出现的情形
	 * 		0. 状态修改 提交的数据和数据库中的数据相同，没关系
	 * 		1. 未执行 --> 执行中，执行完成，过期，取消，其中不能从未执行状态到执行完成
	 * 		2. 执行中 --> 执行完成，其他三种状态报错
	 * 		3. 执行完成 --> 其他四种状态报错
	 * 		4. 取消     --> 其他四种状态报错
	 * 		5. 过期     --> 其他四种状态报错
	 * 	所以初始状态都是从未执行到其他状态，这样就好办了 
	 */
	@Override
	@Transactional
	public void modifySurgeryBookingSituation(SurgeryBooking surgeryBooking) {
		// 首先取出数据库中的该条记录
		System.out.println("modifySurgeryBookingSituation----"+surgeryBooking);
		String situation = surgeryBooking.getSituation();
		String bookingId = surgeryBooking.getBookingId();
		SurgeryBooking surgeryBookingInDatabase = surgeryBookingMapper.selectSurgeryBookingById(bookingId);
		if(surgeryBookingInDatabase.getSituation().equals("1")) {
			
			if("3".equals(situation)) {
				// 未执行，不能直接到执行完成
				throw new SurgeryBookingServiceException("未执行状态不能直接修改为执行完成状态");
			}else if("2".equals(situation)){
				// 未执行到执行状态，需要向执行单中添加一条数据,同时修改状态
				surgeryBookingMapper.updateSurgeryBookingSituation(situation, bookingId);
				SurgeryExe surgeryExe = new SurgeryExe(UUIDUtil.uuid32(), bookingId, 
						surgeryBooking.getInpatientId(), null, null, surgeryBooking.getSurgeryRoomId(), null, null, 
						new Date(), null, null, false, null, null, null, null,null,null);
				surgeryExeMapper.insertSurgeryExe(surgeryExe);
			}
		}else if(surgeryBookingInDatabase.getSituation().equals("2")) {
			System.out.println("数据库中的值"+surgeryBookingInDatabase.getSituation()+":传入的值"+situation);
			// 执行中  --> 执行完成
			if("3".equals(situation)) {
				// 更新状态，同时需要把执行表中的时间记录上
				System.out.println("修改为执行完成状态"+situation);
				surgeryBookingMapper.updateSurgeryBookingSituation(situation, bookingId);
				// 需要把结束的时间填上
				SurgeryExe temp =new  SurgeryExe();
				temp.setBookingId(bookingId);
				temp.setEndTime(new Date());
				surgeryExeMapper.updateSurgeryExeByBookingId(temp);
			}else {
				throw new SurgeryBookingServiceException("不能从执行中状态修改为除执行完成的其他状态");
			}
		}else if(surgeryBookingInDatabase.getSituation().equals("3") && !"3".equals(situation)) {
			throw new SurgeryBookingServiceException("执行完成后不能修改为其他状态");
		}else if(surgeryBookingInDatabase.getSituation().equals("0")) {
			throw new SurgeryBookingServiceException("该单已经取消，不能再改成其他状态，如需手术，请选择新增");
		}else if(surgeryBookingInDatabase.getSituation().equals("4")) {
			throw new SurgeryBookingServiceException("该单已经过期，不能再改成其他状态，如需手术，请选择新增");
		}
	}

}
